using System;
using System.Collections.Generic;
using System.Threading;
using SanFS.DiscLibrary;

namespace SanFS.MediaChangerLibrary
{
	public class MtxDriver : IMediaChangerDriver
	{
		private Mutex           mLock = new Mutex();
		private string          mChangerCmd;
		private IMediaChanger   mMediaChanger;
		private int             mNumDeviceSlots = -1;
				
		public MtxDriver(string ChangerCmd)
		{
			mChangerCmd = ChangerCmd;
		}
		
		public void Reset()
		{
			Console.WriteLine("MtxDriver.Reset(): {0}", mChangerCmd);
			mLock.WaitOne();
			try
			{
				int			slots = -1;
				
				CmdWrapper	cmd = new CmdWrapper(mChangerCmd + " drivestatus");
				string		[]output = cmd.Run();
			
				foreach (string line in output)
				{
					if (line.Trim().StartsWith("Storage Changer"))
						slots = Convert.ToInt32(line.Trim().Split(' ')[4]);
					else if (line.Trim().StartsWith("Status:"))
					{
						if (line.Split(' ')[1] != "OK")
							throw new Exception(String.Format("Bad status from changer ({0})", line));
					}
				}
			
				cmd = new CmdWrapper(mChangerCmd + " unload");
				cmd.Run();
			
				Console.WriteLine("MtxDriver.Reset(): Reset OK ({0} slots detected)", slots);
				mNumDeviceSlots = slots;
				return;
			}
			catch
			{
				throw;
			}
			finally
			{
				mLock.ReleaseMutex();
			}	
		}
		
		public void Load(int ElementNumber)
		{
			mLock.WaitOne();
		 	Console.WriteLine("Mtx.Load(): Slot {0}", ElementNumber);
		 	try
		 	{
		 		CmdWrapper	cmd = new CmdWrapper(mChangerCmd + " load " + ElementNumber);
				string		[]output = cmd.Run();
				
				if (output[1] != "Status: OK")
				{
					Console.WriteLine("Mtx.Load(): Error '{0}'", output[1]);
					throw new Exception("Load failed");
				}
			}
		 	catch
		 	{
		 		throw;
		 	}
		 	finally
		 	{
		 		mLock.ReleaseMutex();
		 	}
		}
		
		public int Unload()
		{
			mLock.WaitOne();
		 	Console.WriteLine("MtxDriver.Unload(): Unloading drive");
		 	try
		 	{
		 		CmdWrapper	cmd = new CmdWrapper(mChangerCmd + " unload");
		 		cmd.MergeStderr = true;
				string		[]output = cmd.Run();
				int			tgtElement = -1;
				
				foreach (string raw in output)
				{
					string	line = raw.Trim();
					
					// Console.WriteLine("Dbg '{0}'", line);
					if (line.Contains("Source Slot Empty"))
					{
						Console.WriteLine("MtxDriver.Unload(): Warning - Drive slot empty");
						return -1;
					}
					
					if (line.StartsWith("Unloading Data Transfer Element"))
						tgtElement = Convert.ToInt32(line.Split(' ')[7].Split('.')[0]);
				}
				
				if (tgtElement == -1)
					throw new Exception("Unloaded a drive but don't know where to!");
		 		Console.WriteLine("Mtx.Unload(): Unloaded into element slot {0}", tgtElement);
		 		return tgtElement;
		 	}
		 	catch
		 	{
		 		throw;
		 	}
		 	finally
		 	{
		 		mLock.ReleaseMutex();
		 	}
		}
		
		public List<IStorageElement> ReadInventory()
		{
			List<IStorageElement>	storageElements = new List<IStorageElement>();
			
			Console.WriteLine("MediaChanger.UpdateInventory(): Updating slot inventory");
			Unload();
			CmdWrapper	cmd = new CmdWrapper(mChangerCmd + " status");
			string		[]output;
		 	 
			mLock.WaitOne();
			try
			{
				output = cmd.Run();
			}
			catch
			{
				throw;
			}
			finally
			{
				mLock.ReleaseMutex();
			}
		 		 
			foreach (string rawLine in output)
			{
				bool		empty = false;
				int			slotNum = -1;
				string		line = rawLine.Trim();
				ElementType	type = ElementType.Normal;
		 		 	
				if (line.StartsWith("Data Transfer Element"))
				{
					slotNum = Convert.ToInt32(line.Split(' ')[3].Split(':')[0]);
		 		 	string	emptyFull = line.Split(' ')[3].Split(':')[1];
		 		 	empty = (emptyFull == "Full") ? false : true;
		 		 	type = ElementType.DataTransfer;
		 		}
				else if (line.StartsWith("Storage Element"))
				{
					string	emptyFull;
		 		 		
					if (line.Contains("IMPORT/EXPORT"))
					{
						slotNum = Convert.ToInt32(line.Split(' ')[2]);
						emptyFull = line.Split(' ')[3].Split(':')[1];
						type = ElementType.ImportExport;
					}
					else
					{
						slotNum = Convert.ToInt32(line.Split(' ')[2].Split(':')[0]);
						emptyFull = line.Split(' ')[2].Split(':')[1];
					}
					empty = (emptyFull == "Full") ? false : true;
				}
		 		 	
				if (slotNum != -1)
					storageElements.Add(StorageElementFactory.CreateStorageElement(type, mMediaChanger, slotNum, empty ? LoadStatus.Empty : LoadStatus.Loaded));
			}
			return storageElements;
		}
		
		public IMediaChanger MediaChanger
		{
		    get { return mMediaChanger; }
		    set { mMediaChanger = value; }
		}

        public int NumDeviceSlots
        {
            get
            {
                if (mNumDeviceSlots == -1)
                    throw new MediaChangerException("NumDeviceSlots cannot be read until device has been reset");
                return mNumDeviceSlots;
            }

        }
	}  // END CLASS
}  // END NAMESPACE
